/**
 * 数据库工具模块
 * 实现了环境感知的消息存储功能，根据运行环境自动选择适合的存储方式
 * - 浏览器环境：使用localStorage存储消息
 * - Electron环境：通过IPC调用主进程的数据库功能
 */

/**
 * 消息接口定义
 * 用于描述聊天消息的数据结构
 */
export interface Message {
  id?: number // 数据库主键ID，可选
  local_id: string // 本地消息ID，客户端生成的唯一标识，用于消息去重和状态更新
  content: string // 消息内容
  type?: string // 消息类型, text: 文本消息, image: 图片消息, file: 文件消息
  status: 0 | 1 | 2 // 消息状态, 0: 未发送, 1: 已发送, 2: 已接收
  timestamp?: string // 发送时间戳，ISO格式
  conversation_id: string // 会话ID，标识消息所属的会话
  sender_id?: string // 发送者ID，标识消息发送者
}

/**
 * 数据库接口定义
 * 统一不同环境下数据库实现的API接口
 */
interface MessageDBInterface {
  /** 初始化数据表结构 */
  initTables(): Promise<void>

  /**
   * 添加新消息
   * @param message 消息对象（不包含id和timestamp）
   * @returns 操作结果，包含插入的ID
   */
  addMessage(message: Omit<Message, 'id' | 'timestamp'>): Promise<any>

  /**
   * 更新消息状态
   * @param local_id 本地消息ID
   * @param status 新的消息状态
   * @returns 操作结果，包含影响的行数
   */
  updateMessageStatus(local_id: string, status: Message['status']): Promise<any>

  /**
   * 获取指定会话的消息列表
   * @param conversationId 会话ID
   * @param limit 限制返回的消息数量，默认30条
   * @returns 消息数组Promise，按时间倒序排列
   */
  getMessagesByConversation(
    conversationId: string,
    limit?: number
  ): Promise<Message[]>

  /**
   * 添加好友申请信息
   * @param friendRequest 好友申请对象
   * @returns 操作结果，包含插入的ID
   */
  addFriendRequest(friendRequest: any): Promise<any>

  /**
   * 获取好友申请列表
   * @returns 好友申请对象数组Promise
   */
  getFriendRequestsByToUserId(toUserId: string, status?: string): Promise<any[]>

  /**
   * 更新好友申请状态
   * @param id 好友申请ID
   * @param status 新的状态
   * @returns 操作结果，包含影响的行数
   */
  updateFriendRequestStatus(id: number, status: string): Promise<any>

  /** 关闭数据库连接 */
  close(): Promise<void>
}

/**
 * 浏览器环境的数据库实现
 * 使用localStorage作为存储介质，实现消息的本地存储
 */
class BrowserMessageDatabase implements MessageDBInterface {
  // localStorage存储键名
  private storageKey = 'chat_messages'

  /**
   * 构造函数
   * 初始化时自动创建存储结构
   */
  constructor() {
    // 异步初始化，但在构造函数中不等待完成
    this.initTables().catch((err) => console.error('初始化数据库失败:', err))
  }

  /**
   * 初始化存储结构
   * 在localStorage中创建初始的空消息数组
   */
  async initTables(): Promise<void> {
    // 检查是否已存在存储数据，不存在则创建
    if (!localStorage.getItem(this.storageKey)) {
      localStorage.setItem(this.storageKey, JSON.stringify([]))
    }
  }

  /**
   * 从localStorage获取所有消息
   * @private 内部方法，用于读取存储的所有消息
   * @returns 消息对象数组
   */
  private getAllMessages(): Message[] {
    const data = localStorage.getItem(this.storageKey)
    return data ? JSON.parse(data) : []
  }

  /**
   * 保存消息到localStorage
   * @private 内部方法，用于将消息数组保存到存储中
   * @param messages 要保存的消息数组
   */
  private saveMessages(messages: Message[]): void {
    localStorage.setItem(this.storageKey, JSON.stringify(messages))
  }

  /**
   * 添加新消息
   * 生成消息ID和时间戳，然后保存到存储中
   * @param message 消息对象
   * @returns 包含插入ID的操作结果
   */
  async addMessage(message: Omit<Message, 'id' | 'timestamp'>): Promise<any> {
    // 获取当前所有消息
    const messages = this.getAllMessages()

    // 创建完整的消息对象，添加ID和时间戳
    const newMessage: Message = {
      ...message,
      id: Date.now(), // 使用时间戳作为简单的唯一ID
      timestamp: new Date().toLocaleString(), // 生成ISO格式时间戳
      type: message.type || 'text' // 默认消息类型为文本
    }

    // 添加到消息列表并保存
    messages.push(newMessage)
    this.saveMessages(messages)

    // 返回类似SQLite的操作结果
    return { lastInsertRowid: newMessage.id }
  }

  /**
   * 更新消息状态
   * 根据本地ID查找消息并更新其状态
   * @param local_id 本地消息ID
   * @param status 新的消息状态
   * @returns 包含影响行数的操作结果
   */
  async updateMessageStatus(
    local_id: string,
    status: Message['status']
  ): Promise<any> {
    // 获取当前所有消息
    const messages = this.getAllMessages()

    // 查找目标消息
    const messageIndex = messages.findIndex((msg) => msg.local_id === local_id)

    // 如果找到消息，更新状态
    if (messageIndex !== -1) {
      messages[messageIndex].status = status
      this.saveMessages(messages)
      return { changes: 1 } // 返回影响的行数
    }

    return { changes: 0 } // 未找到消息，返回0行影响
  }

  /**
   * 获取指定会话的消息列表
   * 按会话ID过滤，按时间戳倒序排列，并限制返回数量
   * @param conversationId 会话ID
   * @param limit 返回消息数量限制
   * @returns 消息数组Promise
   */
  async getMessagesByConversation(
    conversationId: string,
    limit: number = 30
  ): Promise<Message[]> {
    const messages = this.getAllMessages()
    console.log(conversationId)

    // 过滤、排序和分页操作
    const filteredMessages = messages
      .filter((msg) => msg.conversation_id === conversationId) // 按会话ID过滤
      .sort(
        (a, b) =>
          new Date(a.timestamp || 0).getTime() -
          new Date(b.timestamp || 0).getTime()
      ) // 按时间倒序
      .slice(0, limit) // 限制返回数量

    return filteredMessages
  }

  /**
   * 关闭数据库连接
   * 在浏览器实现中，此方法为兼容接口，无需实际关闭操作
   */
  async close(): Promise<void> {
    // 浏览器实现不需要关闭操作
    console.log('Browser database connection closed')
  }
}

/**
 * Electron环境的数据库实现
 * 通过IPC与主进程通信，安全地执行数据库操作
 */
class ElectronMessageDatabase implements MessageDBInterface {
  /**
   * 检查electronAPI是否可用
   * @private 内部方法，用于验证API可用性
   * @returns API是否可用
   */
  private isElectronAPIAvailable(): boolean {
    return (
      typeof window !== 'undefined' &&
      typeof (window as any).electronAPI !== 'undefined' &&
      typeof (window as any).electronAPI.database !== 'undefined'
    )
  }

  /**
   * 初始化数据表结构
   * 通过IPC调用主进程的数据库初始化功能
   */
  async initTables(): Promise<void> {
    if (this.isElectronAPIAvailable()) {
      try {
        console.log('通过IPC初始化数据库表结构')
        await (window as any).electronAPI.database.initTables()
        console.log('数据库表结构初始化成功')
      } catch (error) {
        console.error('数据库表结构初始化失败:', error)
        throw error
      }
    } else {
      console.warn('electronAPI不可用，无法初始化数据库表结构')
      throw new Error('electronAPI不可用')
    }
  }

  /**
   * 添加新消息
   * 通过IPC调用主进程的数据库添加消息功能
   * @param message 消息对象
   * @returns 操作结果Promise
   */
  async addMessage(message: Omit<Message, 'id' | 'timestamp'>): Promise<any> {
    if (this.isElectronAPIAvailable()) {
      try {
        console.log('database -> 通过IPC添加消息:', message)
        const result = await (window as any).electronAPI.database.addMessage(
          message
        )
        console.log('消息添加成功:', result)
        return result
      } catch (error) {
        console.error('消息添加失败:', error)
        throw error
      }
    } else {
      console.warn('electronAPI不可用，无法添加消息')
      throw new Error('electronAPI不可用')
    }
  }

  /**
   * 更新消息状态
   * 通过IPC调用主进程的数据库更新消息状态功能
   * @param local_id 本地消息ID
   * @param status 新的消息状态
   * @returns 操作结果Promise
   */
  async updateMessageStatus(
    local_id: string,
    status: Message['status']
  ): Promise<any> {
    if (this.isElectronAPIAvailable()) {
      try {
        console.log('通过IPC更新消息状态:', local_id, status)
        const result = await (
          window as any
        ).electronAPI.database.updateMessageStatus(local_id, status)
        console.log('消息状态更新成功:', result)
        return result
      } catch (error) {
        console.error('消息状态更新失败:', error)
        throw error
      }
    } else {
      console.warn('electronAPI不可用，无法更新消息状态')
      throw new Error('electronAPI不可用')
    }
  }

  /**
   * 获取指定会话的消息列表
   * 通过IPC调用主进程的数据库获取消息功能
   * @param conversationId 会话ID
   * @param limit 返回消息数量限制
   * @returns 消息数组Promise
   */
  async getMessagesByConversation(
    conversationId: string,
    limit: number = 30
  ): Promise<Message[]> {
    // 返回一个新的Promise，确保消息正确传递
    return new Promise((resolve, reject) => {
      if (this.isElectronAPIAvailable()) {
        try {
          console.log('通过IPC获取会话消息:', conversationId, limit)

          // 直接返回electronAPI调用的Promise结果
          ;(window as any).electronAPI.database
            .getMessagesByConversation(conversationId, limit)
            .then((messages: Message[]) => {
              console.log('获取会话消息成功，共', messages?.length || 0, '条')
              // 确保解析消息数组，防止undefined
              resolve(messages || [])
            })
            .catch((error: any) => {
              console.error('获取会话消息失败:', error)
              resolve([]) // 失败时返回空数组而不是拒绝Promise
            })
        } catch (error) {
          console.error('获取会话消息异常:', error)
          resolve([])
        }
      } else {
        console.warn('electronAPI不可用，无法获取会话消息')
        resolve([])
      }
    })
  }

  /**
   * 添加好友申请信息
   * @param friendRequest 好友申请对象
   * @returns 操作结果，包含插入的ID
   */
  async addFriendRequest(friendRequest: any): Promise<any> {
    if (this.isElectronAPIAvailable()) {
      try {
        console.log('database -> 通过IPC添加好友申请:', friendRequest)
        const result = await (
          window as any
        ).electronAPI.database.addFriendRequest(friendRequest)
        console.log('好友申请添加成功:', result)
        return result
      } catch (error) {
        console.error('好友申请添加失败:', error)
        throw error
      }
    }
  }

  /**
   * 获取好友申请列表
   * @returns 好友申请数组Promise
   */
  async getFriendRequestsByToUserId(
    toUserId: string,
    status?: string
  ): Promise<any[]> {
    return new Promise(async (resolve, reject) => {
      if (this.isElectronAPIAvailable()) {
        try {
          console.log('通过IPC获取好友申请:', toUserId)
          const result = await (
            window as any
          ).electronAPI.database.getFriendRequestsByToUserId(toUserId, status)
          console.log('好友申请获取成功:', result)
          resolve(result || [])
        } catch (error) {
          console.error('好友申请获取失败:', error)
          resolve([])
        }
      } else {
        console.warn('electronAPI不可用，无法获取好友申请')
        resolve([])
      }
    })
  }

  /**
   * 更新好友申请状态
   * @param id 好友申请ID
   * @param status 新状态
   * @returns 操作结果Promise
   */
  async updateFriendRequestStatus(id: number, status: string): Promise<any> {
    if (this.isElectronAPIAvailable()) {
      try {
        console.log('通过IPC更新好友申请状态:', id, status)
        const result = await (
          window as any
        ).electronAPI.database.updateFriendRequestStatus(id, status)
        console.log('好友申请状态更新成功:', result)
        return result
      } catch (error) {
        console.error('好友申请状态更新失败:', error)
        throw error
      }
    }
  }

  /**
   * 关闭数据库连接
   * 通过IPC调用主进程的数据库关闭功能
   */
  async close(): Promise<void> {
    if (this.isElectronAPIAvailable()) {
      try {
        console.log('通过IPC关闭数据库连接')
        await (window as any).electronAPI.database.close()
        console.log('数据库连接关闭成功')
      } catch (error) {
        console.error('关闭数据库连接失败:', error)
        throw error
      }
    } else {
      console.warn('electronAPI不可用，无法关闭数据库连接')
      throw new Error('electronAPI不可用')
    }
  }
}

/**
 * 根据运行环境选择合适的数据库实现
 * @returns 消息数据库实例
 */
function createMessageDB(): MessageDBInterface {
  // 判断是否在Electron环境中
  const isElectron =
    (typeof window !== 'undefined' &&
      (window as any).__electron_preload_loaded) ||
    (window as any).process?.type === 'renderer'

  console.log('检测到Electron环境:', isElectron)

  // 根据环境选择不同的数据库实现
  try {
    if (isElectron) {
      console.log('使用Electron数据库实现')
      return new ElectronMessageDatabase()
    } else {
      console.log('使用浏览器数据库实现')
      return new BrowserMessageDatabase()
    }
  } catch (error) {
    console.error('创建数据库实例失败:', error)
    // 失败时回退到浏览器实现
    console.log('回退到浏览器存储实现')
    return new BrowserMessageDatabase()
  }
}

/**
 * 导出的消息数据库实例
 * 根据运行环境自动选择适合的实现
 */
export const messageDB = createMessageDB()
